package net.sf.midollo.net.server;

import java.io.IOException;
import java.io.InterruptedIOException;

import javax.microedition.io.StreamConnection;

import net.sf.midollo.io.IOStream;
import net.sf.midollo.net.io.StreamConnectionIOStream;
import net.sf.midollo.net.protocol.ProtocolFactory;
import net.sf.midollo.net.protocol.ProtocolRunner;
import net.sf.midollo.utils.List;
import net.sf.midollo.utils.Utils;

public class AsyncAcceptHandler implements AcceptHandler {

  protected final ProtocolFactory protocolFactory;
  protected List requestInfoList;

  protected static class RequestInfo {
    protected IOStream ioRequest;
    protected Thread thread;
  }

  public AsyncAcceptHandler(ProtocolFactory protocolFactory) {
    this.protocolFactory = protocolFactory;
  }

  public void accept(StreamConnection sc) throws IOException {
    Utils.log("accept connection");
    RequestInfo reqInfo = new RequestInfo();
    reqInfo.ioRequest = new StreamConnectionIOStream(sc);
    ProtocolRunner protocolRunner = new ProtocolRunner(reqInfo.ioRequest, this.protocolFactory);
    reqInfo.thread = new Thread(protocolRunner);
    synchronized (this) {
      if (this.requestInfoList == null)
        this.requestInfoList = Utils.newList();
      else
        purgeThreads(false);
      this.requestInfoList.add(reqInfo);
      reqInfo.thread.start();
    }
  }

  public void release() throws IOException {
    synchronized (this) {
      purgeThreads(true);
    }
  }

  protected void purgeThreads(boolean force) throws IOException {
    if (this.requestInfoList == null)
      return;
    for (int i = this.requestInfoList.size() - 1; i >= 0; --i) {
      RequestInfo reqInfo = (RequestInfo)this.requestInfoList.get(i);
      if (!reqInfo.thread.isAlive()) {
        this.requestInfoList.remove(i);
      } else if (force) {
        try {
          reqInfo.ioRequest.close();
        } finally {
          try {
            reqInfo.thread.interrupt();
            try {
              reqInfo.thread.join();
            } catch (InterruptedException ex) {
              throw new InterruptedIOException(ex.toString());
            }
          } finally {
            this.requestInfoList.remove(i);
          }
        }
      }
    }
  }
}
